import Methods from '../common/http-methods'
import Router from 'koa-router'
import invokeController from './invoke-controller'
type Method = Methods | Methods[]
class MethodServe {
    constructor(private field: string, private url: string, private methods: Method) {}
    appendToRouter(router: Router, clazz: FunctionConstructor) {
        if (this.methods) {
            if (this.methods instanceof Array) {
                this.methods.forEach((method) => {
                    router[method](this.url, invokeController(clazz, this.field))
                })
            } else {
                router[this.methods](this.url, invokeController(clazz, this.field))
            }
        } else {
            router.all(this.url, invokeController(clazz, this.field))
        }
    }
}

class ControllerServe {
    setUrl(url: string = '') {
        this.url = url
    }
    setClazz(target: FunctionConstructor) {
        this.clazz = target
    }
    serveMethods(field: string, url: string, method: Method) {
        this.methods.push(new MethodServe(field, url, method))
    }
    private clazz: FunctionConstructor
    private url: string
    private methods: MethodServe[] = []
    appendToRouter(router: Router) {
        let methodRouter = new Router()
        this.methods.forEach((item) => item.appendToRouter(methodRouter, this.clazz))
        let routes = [methodRouter.routes(), methodRouter.allowedMethods()]
        if (this.url != '') {
            router.use(this.url, ...routes)
        } else {
            router.use(...routes)
        }
    }
}

class ControllerServeHolder {
    private controllers = new Map<Function, ControllerServe>()
    makeRouter() {
        let router = new Router()
        for(let controller of this.controllers.values()){
            controller.appendToRouter(router)
        }
        return router
    }
    serve(target: FunctionConstructor, url: string) {
        let t = this.controllers.get(target)
        if (!t) {
            t = new ControllerServe()
            t.setClazz(target)
            this.controllers.set(target, t)
        }
        t.setUrl(url)
    }
    serveMethod(target: FunctionConstructor, field: string, url: string, method: Method) {
        let t = this.controllers.get(target)
        if (!t) {
            t = new ControllerServe()
            t.setClazz(target)
            this.controllers.set(target, t)
        }
        t.serveMethods(field, url, method)
    }
}
export default new ControllerServeHolder()
